﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Reactive.Concurrency;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Markup;

using alib.Enumerable;

using agree.schema;

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// <summary>
/// agree core interface definitions
/// </summary>
/// <remarks>
/// IIdentity is the most fundamental interface in agree and it provides a uniform
/// field -- of type IIdentity -- for every item, representing a traceback of its creation provenance. Although the
/// precise nature of the referenced element tends to be somewhat inconsistent, in those cases where the pipeline 
/// machinery fills in a value (so as to create a record of fan-out scenarios) we can hope for repeatable results.
/// Of some ongoing debate is the traceback mechanism itself, which is supposed to walk back from every object 
/// ultimately to SysObj.Instance. Again, improvement may follow. Another concern is the retention, from a
/// GC perspective, of unwanted or expired items. Additional thought is required for how the end-user might indicate
/// what he or she wishes to preserve.
/// 
/// Non-materialized "worker" objects can be scalar (IAsyncTask) or vector (IActiveObj). These monads
/// have the following properties:
/// 1. Work product that is more than simply compositional of its inputs. Thus, typically long-running;
/// 2. Conceptualizes exactly one well-defined operation. This means that every one of the output item(s) are related to
///	   the single input in some signficant and consistent way.
/// 3. Develops internal state which pertains to this operation;
/// 4. Construction equals binding. That is:
///		a. you must provide exactly one input entity when the monad is created;
///		b. processing automatically starts shortly thereafter
///	5. completion semantics are provided in several ways
///		a. The monad represents an observable sequence of items (IObservable completion semantics)
///		b. The monad returns exactly one IActiveTask (which is typically itself)
///		c. Note that (i.) and (ii.) can be used together. Currently, the system defines this situation as a
///		   serialization, that is, the output monad will not be subscribed until the 
///		   current monad signals completion. Concurrent operation would be equally justifiable.
///		d. If none of the above, then the monad must be assumed to be completed synchronously upon the 
///		   return of the launching function 
///	6. the monad is dead after signalling completion; you can never provide another input.
///	7. Use the XAML 'MarkupExtension' base class
///	
/// There are two types of Transforms, Functors and Monads. Functors differ from monads in the following ways:
/// 1. Represent i.e. composition operations which typically do not care about specific types involved.
/// 2. May not reference any internal state, with the exception of property "getters" or "setters" which are applied to
///		individual outputs.
///	3. Can process additional inputs which are only related to other inputs in that they share the same strong type.
///	4. Associate each input with exactly one output. (Compare to "monads (2.), above)
/// 5. Return results instantaneously and can process additional inputs indefinitely and arbitrarily. (no overall 
///    completion semantics, compare to monads (5.))
/// 6. Not necessary to be a monad or use the 'MarkupExtension' base class
/// 
/// Note that although it might seem like you could implement all functors (except for an initial one) by binding some 
/// Monad to an IObserver input for which you retain the IObservable; this doesn't work due to Mondas#2 vs. Functors#3.
/// When a Monad is in an observable-to-observable configuration, individual input items are not associated with 
/// particular output items; the context is only for the operation as a whole. Even if the monad assumes via special 
/// knowledge that its operation is 1-for-1, there is no formal mechanism for expressing the associations.
/// </remarks>
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
namespace agree
{
	public interface ISchemaObj
	{
	};

	public interface IIdentity : ISchemaObj
	{
		//[DebuggerDisplay("{identity_base._dbg_trace(this),nq}")]
		IIdentity Trace { get; }
	};

	public interface IIdentityId : IIdentity
	{
		long Id { get; }
	}

	/// <summary> http://en.wikipedia.org/wiki/Unit_type </summary>
	public interface IUnit : IIdentity
	{
	};


	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// object graph participation
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

	public interface IRtChild : IIdentity
	{
		IRtParent Parent { get; }
	};

	public interface IRtParent : IIdentity, IServiceProvider
	{
		TaskController TaskControl { get; }
		INameScope NameScope { get; }
	};

	public interface IRtNodeVolatile : IRtParent, IRtChild
	{
	};

	public interface IWorkspace : IRtNodeVolatile, IAddArray<IIdentity>
	{
	};

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// materialized or active collections
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	public interface IItems<out T> : IIdentity
	{
	}

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// materialized collections
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

	public interface IIdentList<out T> : IItems<T>, _IList<T>
	{
	};
	public interface IAddArray<out T> : IIdentList<T>, ρρItemsArr
		where T : IIdentity
	{
		void Add(IIdentity t);
	};
	public interface IIdentAddList<T> : IIdentList<T>, IAddRangeList<T>
	{
	};
	public interface IIdentDict : IIdentity
	{
	};
	public interface IIdentDict<TKey, TValue> : IIdentDict, IDictionary<TKey, TValue>
		where TValue : IIdentity
	{
	};
	public interface IIdentPair<out T> : IIdentity
	{
		T x { get; }
		T y { get; }
	};
	public interface IIdentGroup<out TKey, out TElement> : IGrouping<TKey, TElement>, IIdentList<TElement>, IGrouping
	{
	};
	public interface IIdentMasterGroup<out T> : IIdentGroup<T, T>, IMasterGroup<T>
	{
	};

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// non-materialized collections
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

	public interface IActive<out U> : IRtChild
	{
	};

	public interface IAsyncTask<out U> : IActive<U>, IAsyncResult
	{
		U Result { get; }
		bool TrySetResult(Object value);
	};

	public interface IAsync<out U> : IActive<U>, INotifyCompletion, ICriticalNotifyCompletion
		where U : IIdentity
	{
	};

	public interface IActiveObj<out U> : IActive<U>, IItems<U>, IObservable<U>
	{
	};

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// transforms: functor / monad
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

	public interface ITransform : IIdentity
	{
		Type[] Targs { get; }
	};

	public interface ITransform<in T, out U> : ITransform
	{
	};

	public interface IFunctor : ITransform, IRtNodeVolatile
	{
		Delegate Delegate { get; }
		IFunctor Bind(IFunctor g);
	};

	public interface IFunctor<in T, out U> : IFunctor, ITransform<T, U>
	{
		Func<T, U> Func { get; }
		IFunctor<A, U> Bind<A>(IFunctor<A, T> g);
	};

	public interface IMonad : /* required: MarkupExtension, */ IRtNodeVolatile, ρρInputItemsCount
	{
		Object ProvideValue(IServiceProvider sp);
		bool IsCompleted { get; }
		void Wait();
	};

	public interface IMonad<in T, out U> : IMonad, ITransform<T, U>, IActive<U>
		where U : IIdentity
	{
		/// required:  _ctor(IRtParent parent, T t)
	};

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// thread-safe atomic sequencing
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

	public enum AtomicSeqState { Available = 0, Transact = 1, Hold = 2, Remove = 3 };

	public interface IAtomicSequence : IIdentityId
	{
		void SetSequenceId(ref long next_obj_id);
		bool SeqIdAbove(long i);
		bool SeqIdBelow(long i);
	};

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <summary> interface for any object (grammar or active) that has a surface string associated with it </summary>
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	public interface IString : IIdentityId, ρρText
	{
	};

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// 
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

	public interface ICorpus : IIdentList<IString>
	{
		IReadOnlyList<IString> Items { get; }
	};
}
